﻿/*
Autor...: Ivan M. Kruger
Empresa.: Home Kruger
Data....: 03/03/2011
*/

namespace ik.Impersonator
{
    #region Using directives.
    
    using System;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

    #endregion

    /// http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    public class Impersonator : IDisposable
    {
        #region Public methods.
        public Impersonator(
            string userName,
            string domainName,
            string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }
        #endregion

        #region IDisposable member.
        public void Dispose()
        {
            UndoImpersonation();
        }
        #endregion

        #region P/Invoke.
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        #endregion

        #region Private member.
        private void ImpersonateValidUser(
            string userName,
            string domain,
            string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(
                        userName,
                        domain,
                        password,
                        LOGON32_LOGON_INTERACTIVE,
                        LOGON32_PROVIDER_DEFAULT,
                        ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            impersonationContext = tempWindowsIdentity.Impersonate();
                        }
                        else
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                if (token != IntPtr.Zero)
                {
                    CloseHandle(token);
                }
                if (tokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(tokenDuplicate);
                }
            }
        }

        private void UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;
        #endregion
    }
}

#region "namespace ik.ImpersonatorWindows"
namespace ik.ImpersonatorWindows
{
    //public class IWindows
    //{
    //    /*
    //    Exemplo de uso

    //    System.Security.Principal.WindowsImpersonationContext impersonationContext;
    //    if (!ik.ImpersonatorWindows.IWindows.ImpersonateValidUser("ivan37859", "******", "SALFER", out impersonationContext)) 
    //    { 
    //        throw new Exception("Impersonation failed..."); 
    //    }

    //    using (impersonationContext)
    //    {
    //        your code...
    //    }
    //    */

    //    [System.Runtime.InteropServices.DllImport("advapi32.dll")]
    //    public static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
    //    [System.Runtime.InteropServices.DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
    //    public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
    //    [System.Runtime.InteropServices.DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
    //    public static extern bool RevertToSelf();
    //    [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    //    public static extern bool CloseHandle(IntPtr handle);

    //    public static bool ImpersonateValidUser(String username, String password, String domain, out System.Security.Principal.WindowsImpersonationContext impersonationContext)
    //    {
    //        const int LOGON32_LOGON_INTERACTIVE = 2;
    //        const int LOGON32_PROVIDER_DEFAULT = 0;
    //        System.Security.Principal.WindowsIdentity tempWindowsIdentity;
    //        var token = IntPtr.Zero;
    //        var tokenDuplicate = IntPtr.Zero;
    //        if (RevertToSelf())
    //        {
    //            if (LogonUserA(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
    //            {
    //                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
    //                {
    //                    tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate);
    //                    impersonationContext = tempWindowsIdentity.Impersonate();
    //                    if (impersonationContext != null)
    //                    {
    //                        CloseHandle(token);
    //                        CloseHandle(tokenDuplicate);
    //                        return true;
    //                    }
    //                }
    //            }
    //        }
    //        if (token != IntPtr.Zero)
    //            CloseHandle(token);
    //        if (tokenDuplicate != IntPtr.Zero)
    //            CloseHandle(tokenDuplicate);
    //        impersonationContext = null;
    //        return false;
    //    }
    //}
}
#endregion